////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
//  File name:   SolidBrushObject.h
//  Version:     v1.00
//  Created:     16/9/2004 by Timur.
//  Compilers:   Visual Studio.NET
//  Description: 
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////

#ifndef __SolidBrushObject_h__
#define __SolidBrushObject_h__
#pragma once

#include "Objects\BaseObject.h"
#include "Brush.h"

struct SBrush;
class CEdMesh;

/*!
 *	CTagPoint is an object that represent named 3d position in world.
 *
 */
class CSolidBrushObject : public CBaseObject
{
public:
	DECLARE_DYNCREATE(CSolidBrushObject)

	static void RegisterCommands( CRegistrationContext &rc );
	
	static int s_nCreateNumSides;
	static uint32 s_nGlobalBrushFileId;
	static SBrushCommon::ESolidBrushCreateType s_nCreateType;

	//////////////////////////////////////////////////////////////////////////
	// Ovverides from CBaseObject.
	//////////////////////////////////////////////////////////////////////////
	bool Init( IEditor *ie,CBaseObject *prev,const CString &file );
	void Done();
	void Display( DisplayContext &dc );
	bool CreateGameObject();

	void GetBoundBox( AABB &box );
	void GetLocalBounds( AABB &box );

	bool HitTest( HitContext &hc );

	virtual void SetSelected( bool bSelect );
	virtual IPhysicalEntity* GetCollisionEntity() const;

	//////////////////////////////////////////////////////////////////////////
	void BeginEditParams( IEditor *ie,int flags );
	void EndEditParams( IEditor *ie );
	void BeginEditMultiSelParams( bool bAllOfSameType );
	void EndEditMultiSelParams();

	virtual void EnableEditParams(bool bEnable);
	virtual void EnableEditMultiSelParams(bool bEnable, bool bAllOfSameType);

	//! Called when object is being created.
	virtual	IMouseCreateCallback* GetMouseCreateCallback();

	void Serialize( CObjectArchive &ar );
	XmlNodeRef Export( const CString &levelPath,XmlNodeRef &xmlNode );

	virtual void SetMaterial( CMaterial *mtl );
	virtual void SetMaterial( const CString& materialName );
	virtual void SetMaterialLayersMask( uint32 nLayersMask );
	virtual void SetMinSpec( uint32 nSpec );

	virtual void Validate( CErrorReport *report );
	virtual bool IsSimilarObject( CBaseObject *pObject );
	virtual void OnEvent( ObjectEvent event );

	virtual bool StartSubObjSelection( int elemType );
	virtual void EndSubObjectSelection();
	virtual void CalculateSubObjectSelectionReferenceFrame( ISubObjectSelectionReferenceFrameCalculator* pCalculator );
	virtual void ModifySubObjSelection( SSubObjSelectionModifyContext &modCtx );
	virtual void AcceptSubObjectModify();
	virtual CEdGeometry* GetGeometry();
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	//! Assign brush to object.
	void SetBrush( SBrush* brush );
	//! Retrieve brush assigned to object.
	bool GetBrush(SBrush*& pOutBrush) const;		

	// Call this if you change brush externally.
	void InvalidateBrush();

	// Create a brush from bounding box, returns true if successfully created a brush.
	virtual bool CreateBrush( const AABB &bbox,SBrushCommon::ESolidBrushCreateType createType,int numSides );

	void SelectBrushSide( const Vec3 &raySrc,const Vec3 &rayDir,bool shear );
	void MoveSelectedPoints( const Vec3 &worldOffset );

	//////////////////////////////////////////////////////////////////////////
	// Used by brush exporter.
	//////////////////////////////////////////////////////////////////////////
	Matrix34 GetBrushMatrix() const;
	void SetRenderFlags( int nRndFlags );
	int GetRenderFlags() const { return m_renderFlags; };
	IRenderNode* GetEngineNode() const { return m_pRenderNode; };
	
	void SetViewDistRatio( int nRatio );
	int GetViewDistRatio() const { return m_viewDistRatio; };

	void SetLMQuality( float value ) { m_lightmapQuality = value; }
	float GetLMQuality() const { return m_lightmapQuality; };

	//////////////////////////////////////////////////////////////////////////
	void ResetTransform();
	// Snap all brush points to the grid.
	void SnapPointsToGrid();
	// Save brush to the CGF object.
	void SaveToCgf( const CString filename );
	//////////////////////////////////////////////////////////////////////////

	void PivotToVertices();
	void PivotToCenter();	

	//////////////////////////////////////////////////////////////////////////
	CString GenerateGameFilename();

	bool StartScaling();
	bool GetUntransformedScale( Vec3& scale ) const;
	bool TransformScale( const Vec3& scale );

	void GetVerticesInWorld(std::vector<Vec3>& vertices) const;

public:

	bool MergeSolidObject( const CSolidBrushObject* solid );
	void UpdateBoundBox();
	void DrawTextOn2DBox( DisplayContext &dc, const Vec3& pos, const char* text, float textScale, const ColorF& TextBoxColor );

	static const char* GetSolidDefaultMaterialName(){
		return "EngineAssets/TextureMsg/DefaultSolids";
	}	

protected:
	//! Dtor must be protected.
	CSolidBrushObject();

	virtual void UpdateVisibility( bool visible );

	//! Convert ray given in world coordinates to the ray in local brush coordinates.
	void WorldToLocalRay( Vec3 &raySrc,Vec3 &rayDir );

	bool ConvertFromObject( CBaseObject *object );
	void DeleteThis() { delete this; };
	void InvalidateTM( int nWhyFlags );

	void UpdateEngineNode( bool bOnlyTransform=false );

	void OnFileChange( CString filename );
	

	//////////////////////////////////////////////////////////////////////////
	// Local callbacks.
	void OnRenderVarChange( IVariable *var );
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	// Commands.
	//////////////////////////////////////////////////////////////////////////
	static void Command_ResetTransform();
	static void Command_SnapPointsToGrid();	
	static void Command_MergeBrush();
	static void Command_CSGUnionBrush();
	static void Command_CSGIntersectionBrush();
	static void Command_CSGDifferenceBrush();

	static void DoCSG( SBrushCommon::ECSGOperationEnum csgoperation );


protected:

	int m_brushFlags;
	AABB m_bbox;
	Matrix34 m_invertTM;
	
	Vec3 m_BackupScale;
	//! Solid brush.
	_smart_ptr<SBrush> m_Brush;
	
	// Selected points of this brush.
	SBrushSubSelection m_subSelection;
	//std::vector<Vec3*> m_selectedPoints;

	//! Engine node.
	//! Node that registered in engine and used to render brush prefab
	IRenderNode* m_pRenderNode;

	//////////////////////////////////////////////////////////////////////////
	// Brush rendering parameters.
	//////////////////////////////////////////////////////////////////////////
	int m_renderFlags;
	int m_viewDistRatio;
	float m_lightmapQuality;

	uint32 m_nBrushUniqFileId;

	//////////////////////////////////////////////////////////////////////////
	bool m_bIgnoreNodeUpdate;

	int m_elemType;

	friend class CUndoSolidBrushObject;
};

/*!
 * Class Description of CSolidBrushObject.	
 */
class CSolidBrushObjectClassDesc : public CObjectClassDesc
{
public:
	REFGUID ClassID()
	{
		// {E58B34C2-5ED2-4538-8896-4747FA2B2809}
		static const GUID guid = { 0xe58b34c2, 0x5ed2, 0x4538, { 0x88, 0x96, 0x47, 0x47, 0xfa, 0x2b, 0x28, 0x9 } };

		return guid;
	}
	ObjectType GetObjectType() { return OBJTYPE_SOLID; };
	const char* ClassName() { return "Solid"; };
	const char* Category() { return "Solid"; };
	CRuntimeClass* GetRuntimeClass() { return RUNTIME_CLASS(CSolidBrushObject); };
	const char* GetFileSpec() { return ""; };
	int GameCreationOrder() { return 150; };
};
#endif //__SolidBrushObject_h__
